package session.stateless.SCM;

import entity.SCM.MaterialRequestTemp;
import entity.SCM.MaterialLine;
import entity.SCM.MaterialOrder;
import entity.SCM.MaterialRequest;
import entity.RawMaterial;
import entity.SCM.Supplier;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

@Stateless
public class MaterialOrderBean implements MaterialOrderBeanLocal {

    @PersistenceContext()
    EntityManager em;
    DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");

    private Long lotQuantity(RawMaterial rm, Long q) {
        Long balance = rm.getInventoryBalance();
        if(q>balance){
            if (rm.getLotSize() > 0) {
                if (((q - balance) % rm.getLotSize()) == 0) {
                    return (q - balance) / rm.getLotSize();
                } else {
                    return (q - balance) / rm.getLotSize() + 1;
                }
            } else {
                return q - balance;
            }
        }else{
            return new Long(0);
        }
    }

    @Override
    public MaterialLine createMaterialLine(String rawMaterialName, Long quantity) {
        RawMaterial rm = em.find(RawMaterial.class, rawMaterialName);
        if (rm == null) {
            return null;
        } else {
            MaterialLine ml = new MaterialLine();
            ml.setQuantity(quantity);
            ml.setRawMaterial(rm);
            em.persist(ml);
            em.flush();
            return ml;
        }
    }

    @Override
    public MaterialLine createDummyMLForOrder(String rawMaterialType, Long lotQuantity) {
        RawMaterial rm = em.find(RawMaterial.class, rawMaterialType);
        MaterialLine ml = new MaterialLine();
        ml.setLotQuantity(lotQuantity);
        ml.setRawMaterial(rm);
        return ml;
    }

    @Override
    public RawMaterial getMaterial(String name) {
        RawMaterial rm = em.find(RawMaterial.class, name);
        return rm;
    }

    @Override
    public MaterialLine createMaterialLineForOrderDirectly(MaterialOrder materialOrderToEdit, String rawMaterialType, Long lotQuantity) {
        RawMaterial rm = em.find(RawMaterial.class, rawMaterialType);
        MaterialLine ml = new MaterialLine();
        ml.setLotQuantity(lotQuantity);
        ml.setRawMaterial(rm);
        em.persist(ml);
        em.flush();
        materialOrderToEdit.getMaterialLines().add(ml);
        em.flush();

        return ml;
    }

    @Override
    public MaterialLine createMaterialLineForOrder(MaterialLine mlOld) {
        MaterialLine materialLine = new MaterialLine();
        materialLine.setRawMaterial(mlOld.getRawMaterial());
        if (mlOld.getLotQuantity() == null) {
            materialLine.setLotQuantity(lotQuantity(mlOld.getRawMaterial(), mlOld.getQuantity()));
        } else {
            materialLine.setLotQuantity(mlOld.getLotQuantity());
            materialLine.setQuantity(mlOld.getLotQuantity()*mlOld.getRawMaterial().getLotSize());
        }
        em.persist(materialLine);
        em.flush();
        return materialLine;
    }

    @Override
    public Long createMaterialOrder(String supplierName, List<MaterialLine> mlList, Long materialRequestId) {
        MaterialOrder materialOrder = new MaterialOrder();
        Supplier supplier = em.find(Supplier.class, supplierName);
        materialOrder.setSupplier(supplier);
        Date currentDate = new Date();
        materialOrder.setCurrentDate(dateFormat.format(currentDate));

        if (materialRequestId != null) {
            MaterialRequestTemp mrt = em.find(MaterialRequestTemp.class, materialRequestId);
            MaterialRequest mr = mrt.getMaterialRequest();
            List<MaterialLine> temp = new ArrayList<MaterialLine>();
            for (MaterialLine ml : mlList) {
                if(createMaterialLineForOrder(ml).getLotQuantity()!=0){
                    temp.add(createMaterialLineForOrder(ml));
                }
                for (int i = 0; i < mrt.getMaterialLines().size(); i++) {
                    MaterialLine m = new MaterialLine();
                    m = mrt.getMaterialLines().get(i);
                    if (m.getRawMaterial().getMaterialType().equals(ml.getRawMaterial().getMaterialType())) {
                        m.setRawMaterial(null);
                        mrt.getMaterialLines().remove(i);
                        em.remove(m);
                        em.flush();
                    }
                }

            }
            materialOrder.setMaterialLines(temp);
            materialOrder.setMaterialOrderState(MaterialOrder.State.Pending);
            materialOrder.setMaterialRequestTemp(mrt);

            mrt.getMaterialOrders().add(materialOrder);
            supplier.getMaterialOrderList().add(materialOrder);
            mr.getMaterialOrders().add(materialOrder);
        } else {
            List<MaterialLine> temp = new ArrayList<MaterialLine>();
            for (MaterialLine ml : mlList) {
                temp.add(this.createMaterialLineForOrder(ml));
            }
            materialOrder.setMaterialLines(temp);
            materialOrder.setMaterialOrderState(MaterialOrder.State.Pending);
            materialOrder.setMaterialRequestTemp(null);
        }
        em.persist(materialOrder);
        
        for (MaterialLine temp:materialOrder.getMaterialLines())
            temp.setMaterialOrder(materialOrder);
        supplier.getMaterialOrderList().add(materialOrder);
        em.flush();
        
        return materialOrder.getMaterialOrderId();
    }

    @Override
    public boolean updateMaterialOrder(Long materialOrderId, String supplierName, List<MaterialLine> mls, List<MaterialLine> mrMl) {
        Query q = em.createQuery("SELECT c FROM Supplier c WHERE c.supplierName = :name");
        q.setParameter("name", supplierName);
        Supplier supplier = (Supplier) q.getSingleResult();
        MaterialOrder mo = em.find(MaterialOrder.class, materialOrderId);
        if (supplier != null & mo != null) {
            mo.setSupplier(supplier);
            Date currentDate = new Date();
            mo.setCurrentDate(dateFormat.format(currentDate));
            List<MaterialLine> temp = new ArrayList<MaterialLine>();
            for (int i = 0; i < mls.size(); i++) {
                MaterialLine ml = new MaterialLine();
                if (mls.get(i).getLotQuantity() != null) {
                    ml.setLotQuantity(mls.get(i).getLotQuantity());
                    ml.setRawMaterial(mls.get(i).getRawMaterial());
                    em.persist(ml);
                    em.flush();
                    temp.add(ml);
                }
            }
            mo.setMaterialLines(temp);
            em.flush();

            if (mrMl != null) {
                MaterialRequestTemp mr = mo.getMaterialRequestTemp();
                if (mr != null) {
                    for (int i = 0; i < mrMl.size(); i++) {
                        MaterialLine m = new MaterialLine();
                        m.setLotQuantity(mrMl.get(i).getLotQuantity());
                        m.setRawMaterial(mrMl.get(i).getRawMaterial());
                        em.persist(m);
                        em.flush();
                        mr.getMaterialLines().add(m);
                        em.flush();
                    }
                }
            }
            return true;
        } else {
            System.out.print("Cannot find Material Order");
            return false;
        }
    }
    
    

    @Override
    public boolean deleteMaterialLine(MaterialOrder materialOrder, MaterialLine materialLine) {
        if (materialOrder.getMaterialLines().remove(materialLine) == true) {
            em.remove(materialLine);
            em.flush();
            return true;
        } else {
            System.out.print("Cannot delete Material Line");
            return false;
        }

    }

    @Override
    public List<MaterialOrder> getMaterialOrderForRequest(Long requestId) {
        Query q = em.createQuery("SELECT c FROM MaterialOrder c Where c.materialRequest.materialRequestId = :requestId");
        q.setParameter("requestId", requestId);
        List<MaterialOrder> materialOrderList = q.getResultList();

        return materialOrderList;
    }

    @Override
    public List<MaterialOrder> getAllMaterialOrder() {
        Query q = em.createQuery("SELECT c FROM MaterialOrder c");
        List<MaterialOrder> materialOrderList = new ArrayList<MaterialOrder>();
        for (int i = 0; i < q.getResultList().size(); i++) {
            MaterialOrder mo = (MaterialOrder) q.getResultList().get(i);
            if (mo.getMaterialLines() != null || mo.getMaterialLines().isEmpty()) {
                materialOrderList.add(mo);
            }
        }
        return materialOrderList;
    }

    @Override
    public boolean sendMaterialOrder(MaterialOrder materialOrder) {
        boolean send = false;
        MaterialOrder mo = em.find(MaterialOrder.class, materialOrder.getMaterialOrderId());
        if (mo == null) {
            System.out.println("This MaterialOder Does Not EXIST!");
            return false;
        }
        if (mo.getMaterialOrderState().equals(MaterialOrder.State.Pending)) {
            mo.setMaterialOrderState(MaterialOrder.State.Sent);
            em.flush();
            send = true;
        }
        return send;
    }

    @Override
    public boolean receiveMaterials(MaterialOrder materialOrder) {
        boolean receive = false;
        MaterialOrder mo = em.find(MaterialOrder.class, materialOrder.getMaterialOrderId());
        if (mo == null) {
            System.out.println("This MaterialOder Does Not EXIST!");
            return false;
        }       
        if (mo.getMaterialOrderState().equals(MaterialOrder.State.Sent)) {
            mo.setMaterialOrderState(MaterialOrder.State.Received);
            em.flush();
            receive = true;
        }
        return receive;
    }

    @Override
    public boolean checkMaterialRequest(MaterialRequest mr) {
        List<MaterialOrder> mol = mr.getMaterialOrders();
        for (MaterialOrder mo : mol) {
            if (mo.getMaterialOrderState().equals(MaterialOrder.State.Sent)
                    || mo.getMaterialOrderState().equals(MaterialOrder.State.Pending)) {
                return false;
            }
        }
        return true;
    }

    @Override
    public List<RawMaterial> getMaterial() {
        Query q = em.createQuery("SELECT c FROM RawMaterial c ");
        return q.getResultList();
    }
}
